package com.yanqu.road.server.manger.manor;

import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.config.manor.*;
import com.yanqu.road.entity.config.npc.ManorNpcTalkInfo;
import com.yanqu.road.entity.config.skill.SkillInfo;
import com.yanqu.road.entity.config.skin.SkinInfo;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.eSkillType;
import com.yanqu.road.entity.log.LogManorWeather;
import com.yanqu.road.entity.manor.*;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.entity.player.UserInfo;
import com.yanqu.road.entity.player.UserSkin;
import com.yanqu.road.entity.task.args.ManorRankArgs;
import com.yanqu.road.logic.bussiness.config.NpcConfigBussiness;
import com.yanqu.road.logic.bussiness.player.UserBussiness;
import com.yanqu.road.logic.bussiness.player.UserManorBusiness;
import com.yanqu.road.logic.bussiness.player.UserSkinBusiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.pb.manor.ManorProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.manor.ManorHarvestModel;
import com.yanqu.road.server.gameplayer.module.manor.ManorModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.config.SkillMgr;
import com.yanqu.road.server.manger.config.SkinMgr;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.pb.ManorPb;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.UUIDHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.commons.collections.CollectionUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author ：zfr
 * @date ：2021/5/10 17:40
 */
public class ManorMgr extends TempMgr {
    private static Map<Integer, ManorConfig> manorConfigMap;
    private static Map<Integer, ManorUpgradeConfig> manorUpgradeConfigMap;
    private static Map<Integer, ManorGuestConfig> manorGuestConfigMap;
    private static Map<Integer, ManorTechnologyConfig> manorTechnologyConfigMap;
    private static Map<Integer, ManorNpcTalkInfo> manorNpcTalkInfoMap;
    private static int harvestLvUpProsperousAdd;
    private static int specialSkillLvUpProsperousAdd;
    private static List<Integer> technologySkillLvUpProsperousAdd = new ArrayList<>();
    public static final Object offLineCheckLockObj = new Object();
    public static final Object checkLockObj = new Object();
    private static List<ManorWeatherConfig> manorWeatherConfigList = new ArrayList<>();
    private static List<ManorWeather> manorWeatherList = new ArrayList<>();
    private static List<ManorWeather> saveManorWeatherList = new ArrayList<>();


    public static Map<Integer, ManorConfig> getManorConfigMap() {
        return manorConfigMap;
    }

    public static Map<Integer, ManorUpgradeConfig> getManorUpgradeConfigMap() {
        return manorUpgradeConfigMap;
    }

    public static Map<Integer, ManorGuestConfig> getManorGuestConfigMap() {
        return manorGuestConfigMap;
    }

    public static Map<Integer, ManorTechnologyConfig> getManorTechnologyConfigMap() {
        return manorTechnologyConfigMap;
    }

    public static int getHarvestLvUpProsperousAdd() {
        return harvestLvUpProsperousAdd;
    }

    public static int getSpecialSkillLvUpProsperousAdd() {
        return specialSkillLvUpProsperousAdd;
    }

    public static List<Integer> getTechnologySkillLvUpProsperousAdd() {
        return technologySkillLvUpProsperousAdd;
    }

    public static List<ManorWeather> getManorWeatherList() {
        return manorWeatherList;
    }

    /**
     * 物件是否解锁
     * @param belongRole
     * @param player
     * @return
     */
    public static boolean objectUnLock(int belongRole, GamePlayer player) {
        ManorModule manorModule = player.getModule(ManorModule.class);
        for (ManorHarvestData harvestData : manorModule.getHarvestModel().getHarvestDataMap().values()) {
            if (harvestData.getHarvestType() == belongRole) {
                return true;
            }
        }
        for (ManorBuildingData buildingData : manorModule.getBuildingModel().getBuildingDataMap().values()) {
            ManorConfig manorConfig = ManorMgr.getManorConfigMap().get(buildingData.getId());
            if (manorConfig != null) {
                if (manorConfig.getType() == belongRole){
                    return true;
                }
            }
        }
        return false;
    }

    public static ManorProto.ManorVisitOtherRespMsg.Builder getVisitMsg(long userId) {
        ManorProto.ManorVisitOtherRespMsg.Builder respMsg;
        GamePlayer onlinePlayer = GamePlayerMgr.getOnlinePlayer(userId);
        if (onlinePlayer != null) {
            checkManorHelpRecover(onlinePlayer);
            respMsg = onlinePlayer.getModule(ManorModule.class).getVisitRespMsg();
        } else {
            //离线 查水表
            UserManorData userManorData = UserManorBusiness.getUserManorData(userId);
            Map<Integer, ManorHarvestData> harvestDataMap = UserManorBusiness.getHarvestDataMap(userId);
            Map<Integer, ManorGuestData> guestDataMap = UserManorBusiness.getGuestDataMap(userId);
            Map<Integer, ManorBuildingData> buildingDataMap = UserManorBusiness.getBuildingDataMap(userId);
            UserInfo userInfo = UserMgr.getUserInfo(userId);
            int originHelpCount = userInfo.getManorHelpCount();
            ManorMgr.checkManorHelpRecoverOffLine(userInfo, harvestDataMap, true);
            if (userInfo.getManorHelpCount() != originHelpCount) {
                UserBussiness.updateLastManorHelpRecoverTimeAndCount(userInfo.getUserId(), userInfo.getLastManorHelpRecoverTime(), userInfo.getManorHelpCount());
            }
            if (userManorData == null) {
                respMsg = ManorProto.ManorVisitOtherRespMsg.newBuilder();
                respMsg.setRet(GameErrorCode.E_MANOR_VISIT_PLAYER_MANOR_IS_LOCK);
            } else {
                respMsg = ManorPb.getManorVisitOtherRespMsg(userManorData, harvestDataMap, guestDataMap, buildingDataMap, userInfo);
            }
        }
        return respMsg;
    }

    @Override
    public boolean reloadConfig() throws Exception {
        manorConfigMap = UserManorBusiness.getManorConfigMap();
        manorUpgradeConfigMap = UserManorBusiness.getManorUpgradeConfigMap();
        manorGuestConfigMap = UserManorBusiness.getManorGuestConfigMap();
        manorTechnologyConfigMap = UserManorBusiness.getManorTechnologyConfigMap();
        manorNpcTalkInfoMap = NpcConfigBussiness.getManorNpcTalkInfo();
        String[] split = GameConfig.MANOR_PROSPEROUS_OUTPUT_PARAM.split("\\|");
        harvestLvUpProsperousAdd = Integer.parseInt(split[0]);
        specialSkillLvUpProsperousAdd = Integer.parseInt(split[1]);
        technologySkillLvUpProsperousAdd = new ArrayList<>();
        for (int i = 2; i < split.length; i++) {
            technologySkillLvUpProsperousAdd.add(Integer.parseInt(split[i]));
        }
        parseManorWeatherConfig();
        return true;
    }

    private void parseManorWeatherConfig() {
        manorWeatherConfigList = new ArrayList<>();
        String[] weatherSplit = GameConfig.MANOR_WEATHER_WEIGHT.split("\\|");
        for (int i = 0; i < weatherSplit.length; i++) {
            String weatherTimeConfig = weatherSplit[i];
            String[] weatherTimeSplit = weatherTimeConfig.split(";");
            for (String weather : weatherTimeSplit) {
                String[] split = weather.split(",");
                ManorWeatherConfig config = new ManorWeatherConfig();
                config.setWeather(i + 1);
                config.setMinDurTime(Integer.parseInt(split[0]));
                config.setMaxDurTime(Integer.parseInt(split[1]));
                config.setWeight(Integer.parseInt(split[2]));
                manorWeatherConfigList.add(config);
            }
        }
    }

    @Override
    public boolean reloadData() throws Exception {
        manorWeatherList = UserManorBusiness.getManorWeather();
        return true;
    }

    /**
     * 庄园科技技能加成
     * @param objId
     * @param technologyDataMap
     * @param type
     * @return
     */
    public static int getManorAddValue(int objId, Map<Integer, ManorTechnologyData> technologyDataMap, int type) {
        int addValue = 0;
        if (technologyDataMap != null) {
            for (ManorTechnologyData technologyData : technologyDataMap.values()) {
                ManorTechnologyConfig manorTechnologyConfig = ManorMgr.getManorTechnologyConfigMap().get(technologyData.getId());
                if (manorTechnologyConfig != null) {
                    int pos = 0;
                    for (Integer skillId : manorTechnologyConfig.getVolumesIdList()) {
                        SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
                        if (skillInfo != null) {
                            if (skillInfo.getType() == type) {
                                String objStr = manorTechnologyConfig.getVolumeObjList().get(pos);
                                String[] objArr = objStr.split(";");
                                for (String obj : objArr) {
                                    if (Integer.parseInt(obj) == objId) {
                                        if (technologyData.getSkillLvList().size() - 1 >= pos) {
                                            addValue += SkillMgr.getSkillAddition(skillInfo, technologyData.getSkillLvList().get(pos));
                                        }
                                    }
                                }
                            }
                        }
                        pos++;
                    }
                }
            }
        }
        return addValue;
    }

    /**
     * 获取庄园牧场建筑id
     * @return
     */
    public static int getManorRanchId() {
        for (ManorConfig manorConfig : manorConfigMap.values()) {
            if (manorConfig.getType() == 209) {
                return manorConfig.getId();
            }
        }
        return 0;
    }

    public static List<ManorConfig> getManorInitBuilding() {
        List<ManorConfig> list = new ArrayList<>();
        for (ManorConfig manorConfig : manorConfigMap.values()) {
            if (manorConfig.getUnlock() == 0) {
                list.add(manorConfig);
            }
        }
        return list;
    }

    public static boolean isNpcTalkRefreshTime(UserManorData userManorData) {
        List<Long> refreshTimeList = StringUtils.stringToLongList(GameConfig.MANOR_NPC_EVENT_REFRESH_TIME,";");
        long todayZeroTime = DateHelper.getTodayZeroTimeStamp();
        for(long second : refreshTimeList){
            long refreshTime = todayZeroTime + second*1000;
            if(System.currentTimeMillis() >= refreshTime && userManorData.getRefreshTime() <= refreshTime){
                if(userManorData.isGetReward() || userManorData.getEventId() == 0){
                    return true;
                }else{
                    userManorData.setRefreshTime(System.currentTimeMillis());
                }
            }
        }
        return false;
    }

    public static ManorNpcTalkInfo getRandomNpcTalkEvent(Map<Integer, ManorGuestData> guestDataMap) {
        if (guestDataMap == null || guestDataMap.size() == 0) {
            return null;
        }
        List<ManorNpcTalkInfo> eventList = new ArrayList<>();
        for (ManorNpcTalkInfo npcTalkInfo : manorNpcTalkInfoMap.values()) {
            boolean allHave = true;
            if (npcTalkInfo.getGuestIdList().size() > guestDataMap.size()) {
                allHave = false;
            }
            for (Integer guestId : npcTalkInfo.getGuestIdList()) {
                if (guestId != 0 && !guestDataMap.containsKey(guestId)) {
                    allHave = false;
                }
            }
            if (allHave) {
                eventList.add(npcTalkInfo);
            }
        }

        if (eventList.size() == 0) {
            return null;
        }

        List<Integer> weightList = new ArrayList<>();
        for (ManorNpcTalkInfo npcTalkInfo : eventList) {
            weightList.add(npcTalkInfo.getWeight());
        }
        int index = RandomHelper.getRandomIndexByWeight(weightList);
        return eventList.get(index);
    }

    /**
     * 计算收益
     *
     * @param data
     * @param userInfo
     * @return
     */
    public static void calcYieldOffLine(ManorHarvestData data, long nowTime, UserInfo userInfo) {
        if (data.getBaseSpeed() == 0) {
            Map<Integer, UserSkin> userSkinMap = UserSkinBusiness.getUserSkinMap(userInfo.getUserId());
            Map<Integer, ManorGuestData> guestDataMap = UserManorBusiness.getGuestDataMap(userInfo.getUserId());
            Map<Integer, ManorBuildingData> buildingDataMap = UserManorBusiness.getBuildingDataMap(userInfo.getUserId());
            calcSpeedOffLine(data, userSkinMap, guestDataMap, buildingDataMap, userInfo);
        }
        //玩家协助加成
        BigDecimal helpAddRatio = new BigDecimal(userInfo.getManorHelpCount() * GameConfig.MANOR_HEART_ADDITION_EFFECT);
        data.setHelpAddRatio(helpAddRatio.longValue());
        BigDecimal yield;
        ManorConfig manorConfig = manorConfigMap.get(data.getOutPutId());
        if (manorConfig == null) {
            return;
        }
        if (data.getCollectTime() - data.getRealCollectTime() >= GameConfig.MANOR_OUTPUT_TIME_LIMIT * DateHelper.MINUTE_MILLIONS) {
            data.setCollectTime(nowTime);
            return;
        }
        BigDecimal speed = new BigDecimal(data.getBaseSpeed()).multiply(new BigDecimal(1000).add(new BigDecimal(data.getSpecialSkillAddRatio())))
                .multiply(new BigDecimal(1000).add(new BigDecimal(data.getOtherAddRatio()).add(new BigDecimal(data.getHelpAddRatio())))).divide((BigDecimal.valueOf(1000 * 1000)), 0, BigDecimal.ROUND_UP);
        addRankActivityYieldCount(data, nowTime, speed);
        long canCalcMin = GameConfig.MANOR_OUTPUT_TIME_LIMIT - ((data.getCollectTime() - data.getRealCollectTime()) / DateHelper.MINUTE_MILLIONS);
        long harvestMin = Math.min((nowTime - data.getCollectTime()) / DateHelper.MINUTE_MILLIONS, canCalcMin);
        long lastMillions = (nowTime - data.getCollectTime()) % DateHelper.MINUTE_MILLIONS;
        long collectTime = nowTime - lastMillions;
        data.setCollectTime(collectTime);
        yield = speed.multiply(new BigDecimal(harvestMin)).setScale(0, BigDecimal.ROUND_UP);
        data.setYieldStash(data.getYieldStash() + yield.longValue());
    }

    private static void calcSpeedOffLine(ManorHarvestData data, Map<Integer, UserSkin> userSkinMap, Map<Integer, ManorGuestData> guestDataMap, Map<Integer, ManorBuildingData> buildingDataMap, UserInfo userInfo) {
        calcBaseSpeed(data);
        BigDecimal skinAddRatio = getSkinAddRatio(data, userSkinMap);
        BigDecimal specialAddRatio = getSpecialAddRatio(data);
        BigDecimal guestAddRatio = getGuestAddRatio(data, guestDataMap);
        BigDecimal buildingAddRatio = getBuildingAddRatio(data, buildingDataMap, userSkinMap);
        data.setOtherAddRatio(skinAddRatio.add(guestAddRatio).add(buildingAddRatio).longValue());
        data.setSpecialSkillAddRatio(specialAddRatio.longValue());
    }

    public static void addRankActivityYieldCount(UserManorData userManorData, long yield, GamePlayer player) {
        List<Integer> activityIdList = NormalActivityMgr.getOpenManorRankActivityIdList();
        Map<Integer, Long> rankActivityDataMap = userManorData.getRankActivityDataMap();
        synchronized (rankActivityDataMap) {
            for (Integer activityId : activityIdList) {
                ActivityInfo activityInfo = NormalActivityMgr.getActivityInfo(activityId);
                if (!ActivityMgr.activityInTime(activityInfo)) {
                    continue;
                }
                if (!rankActivityDataMap.containsKey(activityId)) {
                    rankActivityDataMap.put(activityId, 0L);
                }
                long totalYield = rankActivityDataMap.get(activityId) + yield;
                rankActivityDataMap.put(activityId, totalYield);
                userManorData.setUpdateOption();
            }
            rank(player);
        }
    }

    /**
     * 增加活动冲榜需要计入的产量
     * @param manorHarvestData
     */
    public static void addRankActivityYieldCount(ManorHarvestData manorHarvestData, long nowTime, BigDecimal speed) {
        List<Integer> activityIdList = NormalActivityMgr.getOpenManorRankActivityIdList();
        Map<Integer, ManorRankActivityData> rankActivityDataMap = manorHarvestData.getRankActivityDataMap();
        synchronized (rankActivityDataMap) {
            for (Integer activityId : activityIdList) {
                ActivityInfo activityInfo = NormalActivityMgr.getActivityInfo(activityId);
                if (!ActivityMgr.activityInTime(activityInfo)) {
                    continue;
                }
                if (!rankActivityDataMap.containsKey(activityId)) {
                    ManorRankActivityData data = new ManorRankActivityData();
                    data.setActivityId(activityId);
                    data.setYieldCount(0);
                    data.setCalcYieldTime(activityInfo.getBeginTime() * DateHelper.SECOND_MILLIONS);
                    rankActivityDataMap.put(activityId, data);
                }
                ManorRankActivityData data = rankActivityDataMap.get(activityId);
                long collectTime = manorHarvestData.getCollectTime();
                if (data.getCalcYieldTime() < collectTime) {
                    data.setCalcYieldTime(collectTime);
                } else {
                    long lastSecondMillis = manorHarvestData.getCollectTime() % DateHelper.MINUTE_MILLIONS;
                    long curSecondMillis = data.getCalcYieldTime() % DateHelper.MINUTE_MILLIONS;
                    long gapSecondMillis = curSecondMillis - lastSecondMillis;
                    if (gapSecondMillis < 0) {
                        gapSecondMillis = gapSecondMillis + DateHelper.MINUTE_MILLIONS;
                    }
                    data.setCalcYieldTime(data.getCalcYieldTime() - gapSecondMillis);
                    if (data.getCalcYieldTime() < activityInfo.getBeginTime() * DateHelper.SECOND_MILLIONS) {
                        data.setCalcYieldTime(data.getCalcYieldTime() + DateHelper.MINUTE_MILLIONS);
                    }
                    if (data.getCalcYieldTime() > nowTime) {
                        return;
                    }
                }

                long canCalcMin = Math.max(0, GameConfig.MANOR_OUTPUT_TIME_LIMIT - ((data.getCalcYieldTime() - manorHarvestData.getRealCollectTime()) / DateHelper.MINUTE_MILLIONS));
                long harvestMin = Math.min((nowTime - data.getCalcYieldTime()) / DateHelper.MINUTE_MILLIONS, canCalcMin);
                long lastMillions = (nowTime - data.getCalcYieldTime()) % DateHelper.MINUTE_MILLIONS;
                long calcYieldTime = nowTime - lastMillions;
                data.setCalcYieldTime(calcYieldTime);
                data.setYieldCount(data.getYieldCount() + speed.multiply(new BigDecimal(harvestMin)).setScale(0, BigDecimal.ROUND_UP).longValue());
                manorHarvestData.setUpdateOption();
            }
        }
    }

    public static BigDecimal calcBaseSpeed(ManorHarvestData data) {
        ManorConfig manorConfig = ManorMgr.getManorConfigMap().get(data.getOutPutId());
        BigDecimal baseSpeed = BigDecimal.valueOf(manorConfig.getProductionPar().get(0))
                .add(BigDecimal.valueOf(manorConfig.getProductionPar().get(1)).multiply(new BigDecimal(data.getLv() - 1)).divide(new BigDecimal(1000), 0, BigDecimal.ROUND_UP));
        data.setBaseSpeed(baseSpeed.longValue());
        return baseSpeed;
    }

    /**
     * 皮肤加成千分比
     * @param manorHarvestData
     * @return
     */
    public static BigDecimal getSkinAddRatio(ManorHarvestData manorHarvestData, Map<Integer, UserSkin> userSkinMap) {
        BigDecimal skinAddRatio = BigDecimal.ZERO;
        ManorConfig manorConfig = ManorMgr.getManorConfigMap().get(manorHarvestData.getOutPutId());
        if (manorConfig == null) {
            return skinAddRatio;
        }
        for (UserSkin userSkin : userSkinMap.values()) {
            SkinInfo skinInfo = SkinMgr.getSkinInfo(userSkin.getSkinId());
            if (skinInfo == null) {
                continue;
            }
            if (skinInfo.getBelongRole() == manorHarvestData.getHarvestType()) {
                for (Integer skillId : skinInfo.getSkinEffect()) {
                    SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
                    if (skillInfo == null) {
                        continue;
                    }
                    if (skillInfo.getType() == eSkillType.ManorOutPutAddition.getValue()) {
                        skinAddRatio = skinAddRatio.add(BigDecimal.valueOf(SkillMgr.getSkillAddition(skillInfo, userSkin.getLevel())));
                    }
                }
            }
        }
        return skinAddRatio;
    }

    /**
     * 附属技能加成千分比
     * @param manorHarvestData
     * @return
     */
    public static BigDecimal getSpecialAddRatio(ManorHarvestData manorHarvestData) {
        BigDecimal specialAddRatio = BigDecimal.ZERO;
        ManorConfig manorConfig = ManorMgr.getManorConfigMap().get(manorHarvestData.getOutPutId());
        if (manorConfig == null) {
            return specialAddRatio;
        }
        SkillInfo skillInfo = SkillMgr.getSkillInfo(Integer.parseInt(manorConfig.getSkill().split("\\|")[0]));
        long skillAddValue = SkillMgr.getSkillAddition(skillInfo, manorHarvestData.getSpecialSkillLv());
        return BigDecimal.valueOf(skillAddValue);
    }

    /**
     * 住客加成千分比
     * @param manorHarvestData
     * @return
     */
    public static BigDecimal getGuestAddRatio(ManorHarvestData manorHarvestData, Map<Integer, ManorGuestData> guestDataMap) {
        //住客加成
        BigDecimal guestAddRatio = BigDecimal.ZERO;
        ManorConfig manorConfig = ManorMgr.getManorConfigMap().get(manorHarvestData.getOutPutId());
        if (manorConfig == null) {
            return guestAddRatio;
        }
        if (guestDataMap == null) {
            return guestAddRatio;
        }
        for (ManorGuestData guestData : guestDataMap.values()) {
            int guestDataId = guestData.getId();
            ManorGuestConfig manorGuestConfig = ManorMgr.getManorGuestConfigMap().get(guestDataId);
            if (manorGuestConfig == null) {
                continue;
            }
            int skillId = manorGuestConfig.getSkill();
            SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
            if (skillInfo != null) {
                if (skillInfo.getType() == eSkillType.ManorOutPutAddition.getValue()) {
                    Integer parC = skillInfo.getParamList().get(2);
                    if (parC == 0 || parC == manorConfig.getClassification()) {
                        guestAddRatio = guestAddRatio.add(BigDecimal.valueOf(SkillMgr.getSkillAddition(skillInfo, 1)));
                    }
                }
            }
            List<Integer> skinIdList = guestData.getSkinIdList();
            for (Integer skinId : skinIdList) {
                ManorGuestConfig skinConfig = ManorMgr.getManorGuestConfigMap().get(skinId);
                if (skinConfig != null) {
                    SkillInfo skinSkill = SkillMgr.getSkillInfo(skinConfig.getSkill());
                    if (skinSkill != null) {
                        if (skinSkill.getType() == eSkillType.ManorOutPutAddition.getValue()) {
                            int parC = skinSkill.getParamList().get(2);
                            if (parC == 0 || parC == manorConfig.getClassification()) {
                                guestAddRatio = guestAddRatio.add(BigDecimal.valueOf(SkillMgr.getSkillAddition(skinSkill, 1)));
                            }
                        }
                    }
                }
            }
        }
        return guestAddRatio;
    }

    public static BigDecimal getBuildingAddRatio(ManorHarvestData manorHarvestData, Map<Integer, ManorBuildingData> buildingDataMap, Map<Integer, UserSkin> userSkinMap) {
        BigDecimal buildingAddRatio = BigDecimal.ZERO;
        ManorConfig manorConfig = ManorMgr.getManorConfigMap().get(manorHarvestData.getOutPutId());
        if (manorConfig == null) {
            return buildingAddRatio;
        }
        if (buildingDataMap != null) {
            for (ManorBuildingData buildingData : buildingDataMap.values()) {
                ManorConfig buildingConfig = ManorMgr.getManorConfigMap().get(buildingData.getId());
                if (buildingConfig != null) {
                    SkillInfo skillInfo = SkillMgr.getSkillInfo(Integer.parseInt(buildingConfig.getSkill()));
                    if (skillInfo != null) {
                        if (skillInfo.getType() == eSkillType.ManorOutPutAddition.getValue()) {
                            int parC = skillInfo.getParamList().get(2);
                            if (parC == 0 || parC == manorConfig.getClassification()) {
                                buildingAddRatio = buildingAddRatio.add(BigDecimal.valueOf(SkillMgr.getSkillAddition(skillInfo, 1)));
                            }
                        }
                    } else {
                        if (Integer.parseInt(buildingConfig.getSkill()) != 0) {
                            getLogger().error("skillInfo is null, buildingConfigId :{} , skillId :{}", buildingConfig.getId(), buildingConfig.getSkill());
                        }
                    }
                }
                for (UserSkin userSkin : userSkinMap.values()) {
                    SkinInfo skinInfo = SkinMgr.getSkinInfo(userSkin.getSkinId());
                    if (skinInfo == null) {
                        continue;
                    }
                    if (buildingConfig != null && skinInfo.getBelongRole() == buildingConfig.getType()) {
                        for (int skillId : skinInfo.getSkinEffect()) {
                            SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
                            if (skillInfo == null) {
                                continue;
                            }
                            if (skillInfo.getType() == eSkillType.ManorOutPutAddition.getValue()) {
                                int parC = skillInfo.getParamList().get(2);
                                if (parC == 0 || parC == manorConfig.getClassification()) {
                                    buildingAddRatio = buildingAddRatio.add(BigDecimal.valueOf(SkillMgr.getSkillAddition(skillInfo, userSkin.getLevel())));
                                }
                            }
                        }
                    }
                }
            }
        }
        return buildingAddRatio;
    }

    public static void checkManorHelpRecoverOffLine(UserInfo userInfo, Map<Integer, ManorHarvestData> harvestDataMap, boolean isVisit) {
        synchronized (offLineCheckLockObj) {
            boolean isRecover = false;
            while (userInfo.getManorHelpCount() > 0 && System.currentTimeMillis() - userInfo.getLastManorHelpRecoverTime() >= GameConfig.MANOR_HEART_RECOVER_TIME * DateHelper.SECOND_MILLIONS) {
                isRecover = true;
                long recoverAfterTime = userInfo.getLastManorHelpRecoverTime() + GameConfig.MANOR_HEART_RECOVER_TIME * DateHelper.SECOND_MILLIONS;
                for (ManorHarvestData data : harvestDataMap.values()) {
                    ManorMgr.calcYieldOffLine(data, recoverAfterTime, userInfo);
                }
                userInfo.setManorHelpCount(userInfo.getManorHelpCount() - 1);
                userInfo.setLastManorHelpRecoverTime(recoverAfterTime);
            }
            if (isRecover && isVisit) {
                for (ManorHarvestData data : harvestDataMap.values()) {
                    UserManorBusiness.update(data);
                }
            }
        }
    }

    public static void calcReward(ManorHarvestData data, Property getReward) {
        ManorConfig manorConfig = ManorMgr.getManorConfigMap().get(data.getOutPutId());
        BigDecimal speed = new BigDecimal(data.getBaseSpeed()).multiply(new BigDecimal(1000).add(new BigDecimal(data.getSpecialSkillAddRatio())))
                .multiply(new BigDecimal(1000).add(new BigDecimal(data.getOtherAddRatio()))).divide((BigDecimal.valueOf(1000 * 1000)), 0, BigDecimal.ROUND_UP);
        getReward.addProperty(manorConfig.getProduction(), BigInteger.valueOf(speed.multiply(new BigDecimal(GameConfig.MANOR_HEART_REWARDS_TIME)).longValue()));
    }

    public static ManorHelpRecord initManorHelpRecord(long helpUserId, long userId, UserBaseInfo userBaseInfo) {
        ManorHelpRecord manorHelpRecord = new ManorHelpRecord();
        manorHelpRecord.setRecordUid(UUIDHelper.randomUUID(String.valueOf(GameServer.getInstance().getServerId())));
        manorHelpRecord.setRecordTime(System.currentTimeMillis());
        manorHelpRecord.setUserId(helpUserId);
        manorHelpRecord.setOperateUserId(userId);
        manorHelpRecord.setOperateBaseInfo(userBaseInfo);
        manorHelpRecord.setInsertOption();
        return manorHelpRecord;
    }

    public static void checkManorHelpRecover(GamePlayer player) {
        synchronized (checkLockObj) {
            UserInfo userInfo = UserMgr.getUserInfo(player.getUserId());
            if (userInfo == null) {
                return;
            }
            boolean isRecover = false;
            while (userInfo.getManorHelpCount() > 0 && System.currentTimeMillis() - userInfo.getLastManorHelpRecoverTime() >= GameConfig.MANOR_HEART_RECOVER_TIME * DateHelper.SECOND_MILLIONS) {
                isRecover = true;
                long recoverAfterTime = userInfo.getLastManorHelpRecoverTime() + GameConfig.MANOR_HEART_RECOVER_TIME * DateHelper.SECOND_MILLIONS;
                ManorHarvestModel harvestModel = player.getModule(ManorModule.class).getHarvestModel();
                Map<Integer, ManorHarvestData> harvestDataMap = harvestModel.getHarvestDataMap();
                for (ManorHarvestData data : harvestDataMap.values()) {
                    harvestModel.calcYield(data, recoverAfterTime, true);
                }
                userInfo.setManorHelpCount(userInfo.getManorHelpCount() - 1);
                userInfo.setLastManorHelpRecoverTime(recoverAfterTime);
            }
            if (isRecover) {
                player.getModule(ManorModule.class).syncManorData();
            }
        }
    }

    public static void harvestRank(Map<Integer, ManorHarvestData> harvestDataMap, GamePlayer player) {
        //产量冲榜
        UserManorData userManorData = player.getModule(ManorModule.class).getUserManorData();
        List<Integer> activityIdList = NormalActivityMgr.getOpenManorRankActivityIdList();
        Map<Integer, Long> rankActivityDataMap = userManorData.getRankActivityDataMap();
        synchronized (rankActivityDataMap) {
            for (Integer activityId : activityIdList) {
                ActivityInfo activityInfo = NormalActivityMgr.getActivityInfo(activityId);
                if (!ActivityMgr.activityInTime(activityInfo)) {
                    continue;
                }
                if (!rankActivityDataMap.containsKey(activityId)) {
                    rankActivityDataMap.put(activityId, 0L);
                }
                long totalYield = rankActivityDataMap.get(activityId);
                for (ManorHarvestData manorHarvestData : harvestDataMap.values()) {
                    ManorRankActivityData manorRankActivityData = manorHarvestData.getRankActivityDataMap().get(activityId);
                    if (manorRankActivityData != null) {
                        totalYield += manorRankActivityData.getYieldCount();
                        manorRankActivityData.setYieldCount(0L);
                        manorHarvestData.setUpdateOption();
                    }
                }
                rankActivityDataMap.put(activityId, totalYield);
                userManorData.setUpdateOption();
            }
            rank(player);
        }

    }

    public static void rank(GamePlayer player) {
        //产量冲榜
        ManorRankArgs args = new ManorRankArgs(player.getModule(ManorModule.class).getUserManorData().getRankActivityDataMap());
        player.notifyListener(eGamePlayerEventType.ManorOutPutCountRank.getValue(), args);
    }

    public static void checkWeatherChange() {
        synchronized (manorWeatherList) {
            boolean needSync = false;
            long nowTime = System.currentTimeMillis();
            if (manorWeatherList.size() == 0 || manorWeatherList.get(0).getEndTime() <= nowTime) {
                int curWeather = 0;
                long beginTime = nowTime;
                while (manorWeatherList.size() > 0 && manorWeatherList.get(0).getEndTime() <= nowTime) {
                    manorWeatherList.remove(0);
                }
                while (manorWeatherList.size() < 2) {
                    if (manorWeatherList.size() > 0) {
                        ManorWeather manorWeather = manorWeatherList.get(0);
                        curWeather = manorWeather.getWeather();
                        beginTime = manorWeather.getEndTime();
                    }
                    manorWeatherList.add(randomWeather(curWeather, beginTime));
                    needSync = true;
                }
                if (needSync) {
                    for (GamePlayer player : GamePlayerMgr.getAllOnlinePlayer()) {
                        player.getModule(ManorModule.class).syncManorData();
                    }
                }
            }
        }
    }

    private static ManorWeather randomWeather(int curWeather, long beginTime) {
        List<ManorWeatherConfig> randomList = manorWeatherConfigList.stream().filter(config -> config.getWeather() != curWeather).collect(Collectors.toList());
        List<Integer> weightList = randomList.stream().map(ManorWeatherConfig::getWeight).collect(Collectors.toList());
        int index = RandomHelper.getRandomIndexByWeight(weightList);
        ManorWeatherConfig config = randomList.get(index);
        ManorWeather manorWeather = new ManorWeather();
        manorWeather.setWeather(config.getWeather());
        manorWeather.setEndTime(beginTime + (new RandomHelper().next(config.getMinDurTime(), config.getMaxDurTime()) * DateHelper.MINUTE_MILLIONS));
        synchronized (saveManorWeatherList) {
            saveManorWeatherList.add(manorWeather);
        }
        LogMgr.addLogManorWeather(new LogManorWeather(manorWeather.getWeather(), manorWeather.getEndTime(), new Date()));
        return manorWeather;
    }

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean stop() {
        return false;
    }

    @Override
    public boolean save() {
        if (!CollectionUtils.isEmpty(saveManorWeatherList)) {
            List<ManorWeather> list;
            synchronized (saveManorWeatherList) {
                list = new ArrayList<>(saveManorWeatherList);
                saveManorWeatherList.clear();
            }
            UserManorBusiness.insertManorWeather(list);
        }
        return true;
    }

    private static int checkManorHelp(long helpUserId, boolean isCross, GamePlayer player){
        UserInfo userInfo = UserMgr.getUserInfo(helpUserId);
        if (null == userInfo) {
            return GameErrorCode.E_USER_NO_FOUND;
        }
        if (userInfo.getManorHelpCount() >= GameConfig.MANOR_HEART_MAX_COUNT) {
            return GameErrorCode.E_MANOR_BE_HELP_COUNT_LIMIT;
        }
        if(!isCross){
            if (!player.getModule(CurrencyModule.class).removeCurrency(PropertyHelper.parseStringToProperty(GameConfig.MANOR_HEART_CONSUME),
                    eLogMoneyType.Manor, eLogMoneyType.ManorHelpPlayerCost)) {
                return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
            }
        }
        return 0;
    }

    public static ManorHelpResult onlineManorHelp(long userId, UserBaseInfo userBaseInfo, boolean isCross, GamePlayer player,
                                                  GamePlayer helpPlayer, long helpUserId){
        ManorHelpResult manorHelpResult = new ManorHelpResult();
        int result = checkManorHelp(helpUserId, isCross, player);
        if(0 != result){
            manorHelpResult.setRet(result);
            return manorHelpResult;
        }
        long nowTime = System.currentTimeMillis();
        ManorHelpRecord manorHelpRecord = ManorMgr.initManorHelpRecord(helpUserId, userId, userBaseInfo);
        Property getReward = new Property();
        Map<Integer, ManorHarvestData> harvestDataMap = helpPlayer.getModule(ManorModule.class).getHarvestModel().getHarvestDataMap();
        for (ManorHarvestData data : harvestDataMap.values()) {
            helpPlayer.getModule(ManorModule.class).getHarvestModel().calcYield(data, nowTime, false);
            ManorMgr.calcReward(data, getReward);
        }
        UserInfo userInfo = UserMgr.getUserInfo(helpUserId);
        int manorHelpCount = userInfo.getManorHelpCount();
        manorHelpCount++;
        if (manorHelpCount == 1) {
            userInfo.setLastManorHelpRecoverTime(System.currentTimeMillis());
        }
        userInfo.setManorHelpCount(manorHelpCount);
        for (ManorHarvestData data : harvestDataMap.values()) {
            helpPlayer.getModule(ManorModule.class).getHarvestModel().calcSpeed(data, true);
        }
        helpPlayer.getModule(ManorModule.class).addManorHelpRecord(manorHelpRecord);
        manorHelpResult.setReward(getReward);
        manorHelpResult.setManorHelpCount(manorHelpCount);
        return manorHelpResult;
    }

    public static ManorHelpResult offlineManorHelp(long userId, UserBaseInfo userBaseInfo, boolean isCross, GamePlayer player, long helpUserId){
        ManorHelpResult manorHelpResult = new ManorHelpResult();
        int result = checkManorHelp(helpUserId, isCross, player);
        if(0 != result){
            manorHelpResult.setRet(result);
            return manorHelpResult;
        }
        long nowTime = System.currentTimeMillis();
        ManorHelpRecord manorHelpRecord = ManorMgr.initManorHelpRecord(helpUserId, userId, userBaseInfo);
        UserInfo userInfo = UserMgr.getUserInfo(helpUserId);
        int manorHelpCount = userInfo.getManorHelpCount();
        Map<Integer, ManorHarvestData> harvestDataMap = UserManorBusiness.getHarvestDataMap(userInfo.getUserId());
        ManorMgr.checkManorHelpRecoverOffLine(userInfo, harvestDataMap, false);
        manorHelpCount++;
        Property getReward = new Property();
        for (ManorHarvestData data : harvestDataMap.values()) {
            ManorMgr.calcYieldOffLine(data, nowTime, userInfo);
            ManorMgr.calcReward(data, getReward);
            data.setHelpAddRatio(manorHelpCount * GameConfig.MANOR_HEART_ADDITION_EFFECT);
            UserManorBusiness.update(data);
        }
        userInfo.setManorHelpCount(manorHelpCount);
        if (manorHelpCount == 1) {
            userInfo.setLastManorHelpRecoverTime(nowTime);
            UserBussiness.updateLastManorHelpRecoverTimeAndCount(helpUserId, nowTime, manorHelpCount);
        } else {
            UserBussiness.updateManorHelpCount(helpUserId, manorHelpCount);
        }
        UserManorBusiness.addManorHelpRecord(manorHelpRecord);
        manorHelpResult.setReward(getReward);
        manorHelpResult.setManorHelpCount(manorHelpCount);
        return manorHelpResult;
    }
}
